#ifndef ELIMINATIONBOX_H_JM_20130220
#define ELIMINATIONBOX_H_JM_20130220

// ## 
#include "../BufferedOutputBox.h"
#include "../../LogConf.h"
#include "../../common_bbx/sharedBoxData/HashTableHolder.h"

namespace jm4bbx {

	template<typename policyT, typename keyT>
	class  EliminationBox : public BufferedOneOutputBox<BinaryOperationResultIndexType> {
				JM_USE_LOGGER(boxes_hash1step_eliminationBox_logger)
	public:

		static const  groupType INPUT_GROUP;
		static const  groupType OUTPUT_GROUP;	
		static const  columnType INPUT_COLUMN;
		static const  columnType OUTPUT_COLUMN;
		static const  inType IN_ARC;
		static const  outType OUT_ARC;

		/// Typ politiky.
		typedef policyT policyType;
		/// Typ prenasanych dat medzi boxami.
		typedef KeyRecord<keyT> transferValueType;
		/// Typ holdra tabulky.
		typedef HashTableHolder<keyT> HTH;

		EliminationBox(const BoxParamPack& p) 
			: BufferedOneOutputBox(p, OUTPUT_GROUP, OUTPUT_COLUMN, OUT_ARC) { }

		virtual void initImpl() {
			add_group(INPUT_GROUP, INPUT_COLUMN, 
				get_input_descriptors(IN_ARC));

			add_group(OUTPUT_GROUP, OUTPUT_COLUMN, 
				get_output_descriptors(OUT_ARC));

			initBufferedOutputs();
			wait4Receive();
		}


		virtual void syncMachEtwas() {

			GroupPtr ig = getGroupPtr(INPUT_GROUP);
		

			// Budem vkladat prvky do hash tabulky -> zapnem synchronizaciu.
			HTH::getHashTable()->setSynchronized(true);

			for (; ig->getReadPosition() < ig->getReadEnd() && !isOutputFull(); 
				ig->moveReadPosition()) {								
				
				transferValueType value = 
					get_data<policyType>(INPUT_COLUMN)[ig->getReadPosition()];				

				auto key = value.getKey();

				if (HTH::getHashTable()->addIf(key, 
					HTH::ValueType(value.getIndex(), key), 
					jmlib::HashRowActionCondition::HAS_NOT_KEY)) {
					// Zaznam vlozeny do hash tabulky -> poslem ho aj na vystup
						BinaryOperationResultIndex index = 
							{value.getIndex(), -1};	
						addOutputData(index);

						LOG_D("Record: " << key << "-> insert")
				}
				else {
					LOG_D("Record: " << key << "  -> nothing")
				}
			}
			// Priechod datami ktore sa maju spracovat. 
			sendOutputData();

			// Pokial je vstup spracovany cely ...
			if (!(ig->getReadPosition() < ig->getReadEnd())) {
				// a vystup je uz cely aj odoslany -> koniec prace boxu.
				if (isOutputEmpty()) {
					send_poisoned(OUT_ARC); // Aby ciel vedel ze je hotovo!!!
					sendSignalsOut(true);
					wait4Receive();
				} 
			}
			// V opacnom pripade nerobim nic a necham box opat naplanovat 
			// nech dokonci svoju cinnost.
		}
	private:	
		/// Zahajenie cakania na vstup.
		void wait4Receive() {
			receive(IN_ARC, INPUT_GROUP);
		}
	};
	template<class T1, class T2>
	const  outType EliminationBox<T1, T2>::OUT_ARC = 
		outType(0);

	template<class T1, class T2>
	const  inType EliminationBox<T1, T2>::IN_ARC = 
		inType(0);

	template<class T1, class T2>
	const  columnType EliminationBox<T1, T2>::OUTPUT_COLUMN = 
		columnType(1);

	template<class T1, class T2>
	const  columnType EliminationBox<T1, T2>::INPUT_COLUMN = 
		columnType(0);

	template<class T1, class T2>
	const  groupType EliminationBox<T1, T2>::OUTPUT_GROUP = 
		groupType(1);

	template<class T1, class T2>
	const  groupType EliminationBox<T1, T2>::INPUT_GROUP = 
		groupType(0);

} // namespace jm4bbx


#endif
